/*******************************************************************************
* @copyright: Shenzhen Hangshun Chip Technology R&D Co., Ltd
* @filename:  hk32c030xx_ts.c
* @brief:     This file provides firmware functions to manage the following
*             functionalities of the Temperature sensor (TS) peripheral:
*             + Initialization and Configuration
*             + Power saving
*             + Temperature ALARM configuration
*             + Temperature Calibration Configuration
*             + Interrupts and flags management
* @author:    AE Team
* @version:   V1.0.0/2023-11-15
*             1.Initial version
* @log:
*******************************************************************************/


/* Includes ------------------------------------------------------------------*/
#include "hk32c030xx_ts.h"
#include "hk32c030xx_rcc.h"

/** @addtogroup HK32C030xx_StdPeriph_Driver
  * @{
  */

/** @defgroup TS   TS
  * @brief TS driver modules
  * @{
  @verbatim
================================================================================
                      ##### How to use this driver #####
================================================================================
    [..]
    (#) Enable the TS interface clock using
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TEMPSEN, ENABLE);
    (#) Configure the TS Clock, start up time, Sample delay, Average and external trigger
        using the TS_Init() function.
    (#) Activate the TS peripheral using TS_Cmd() function.

    *** TS configuration ***
    ============================================
    [..]
    (+) To configure the TS features, use TS_Init() function.
    (+) To activate the Alarm mode, use the TS_ALARMCmd() function.
    (+) To activate the Average mode, use the TS_AVERAGE() function.
    (+) To activate the external trigger mode, use the TS_TRGOEXTSEL() functions.
    (+) To activate the calibration , use the TS_GetCalibrationFactor() functions.
    (+) To read the TS converted values, use the TS_GetConversionValue()
        function.
   @endverbatim
 */


/** @defgroup TS_PERIPH_Constants  TS_PERIPH_Constants
  * @{
  */
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/

/* Calibration time out */
#define CALIBRATION_TIMEOUT       ((uint32_t)0x00000F00)
#define PWR_VREFINT_BUF        *(uint32_t *)((uint32_t)0x40007070)
#define TS_CAL        *(uint32_t *)((uint32_t)0x1ffff9a8)
/**
  * @}
  */
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/** @defgroup TS_Private_Functions    TS_Private_Functions
  * @{
  */

/** @defgroup TS_Group1 Initialization and Configuration functions
 *  @brief   Initialization and Configuration functions
 *
@verbatim
 ===============================================================================
          ##### Initialization and Configuration functions #####
 ===============================================================================
    [..] This section provides functions allowing to:
        (+) Initialize and configure the TS Prescaler
        (+) External trigger Edge and source
        (+) Enable or disable the TS peripheral

@endverbatim
  * @{
  */

/**
  * @brief  Deinitializes TS peripheral registers to their default reset values.
  * @retval None
  */
void TS_DeInit(void)
{
    /* Enable TS reset state */
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_TEMPSEN, ENABLE);
    /* Release TS from reset state */
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_TEMPSEN, DISABLE);
}

/**
  * @brief  Initializes the TS peripheral according to the specified parameters
  *         in the TS_InitStruct.
  * @note   This function is used to configure the global features of the TS (
  *         TS Clock, start up time, Alarm, Sample delay, Average and external trigger).
  * @param  TS_InitStruct: pointer to an TS_InitTypeDef structure that contains
  *         the configuration information for the specified TS peripheral.
  * @retval None
  */
void TS_Init(TS_InitTypeDef* TS_InitStruct)
{
    uint32_t tmpreg = 0;
    uint32_t tmpth = 0;
    /* Check the parameters */
    assert_param(IS_TS_CLOCKMODE(TS_InitStruct->TS_ClockDIV));
    assert_param(IS_TS_ANASTUP(TS_InitStruct->TS_ANASTUP));
    assert_param(IS_TS_SMPDLY(TS_InitStruct->TS_SMPDLY));
    assert_param(IS_TS_ALARM(TS_InitStruct->TS_ALARM));
    assert_param(IS_TS_EXT_TRIG_EDGE(TS_InitStruct->TS_EXTEN));
    assert_param(IS_TS_EXTERNAL_TRIG_CONV(TS_InitStruct->TS_EXTSEL));
    assert_param(IS_TS_AVERAGE(TS_InitStruct->TS_AVERAGE));
    /*---------------------------- TS CR Configuration ---------------------*/
    /* Set DIV[2:0] bits according to TS_ClockDIV value */
    /* Set ANASTUP[2:0] bits according to TS_ANASTUP value */
    /* Set SMPDLY[3:0] bits according to TS_SMPDLY value */
    /* Set ALARM[1:0] bits according to TS_ALARM value */
    /* Set EXTEN[1:0] bits according to TS_EXTEN value */
    /* Set EXTSEL[2:0] bits according to TS_EXTSEL value */
    /* Set AVERAGE[2:0] bits according to TS_AVERAGE value */
    tmpreg  |= (TS_InitStruct->TS_ClockDIV | TS_InitStruct->TS_ANASTUP | TS_InitStruct->TS_SMPDLY | TS_InitStruct->TS_ALARM |
                TS_InitStruct->TS_EXTEN | TS_InitStruct->TS_EXTSEL | TS_InitStruct->TS_AVERAGE);
    tmpth = ((TS_InitStruct->TS_HIGH_ALARM_TH) << 16) + TS_InitStruct->TS_LOW_ALARM_TH;
    /* Write to TS CR */
    TS->CR = tmpreg;
    /* Write to TS THR */
    TS->THR = tmpth;
    /*Open Vrefint buf */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
    PWR_VREFINT_BUF |= 0x0D;
    /*Set the Calibration data to the TS peripheral */
    TS->CALR = (uint8_t)TS_CAL;
}

/**
  * @brief  Fills each TS_InitStruct member with its default value.
  * @note   This function is used to initialize the global features of the TS (
  *         TS Clock, start up time, Alarm, Sample delay, Average and external trigger).
  * @param  TS_InitStruct: pointer to an TS_InitTypeDef structure which will
  *         be initialized.
  * @retval None
  */
void TS_StructInit(TS_InitTypeDef* TS_InitStruct)
{
    /* Reset TS init structure parameters values */
    /* Initialize the TS_ClockDIV member */
    TS_InitStruct->TS_ClockDIV = TS_ClockDIV8;
    /* Initialize the TS_ANASTUP member */
    TS_InitStruct->TS_ANASTUP = TS_ANASTUP4;
    /* Initialize the TS_SMPDLY member */
    TS_InitStruct->TS_SMPDLY = TS_SMPDLY1;
    /* Initialize the TS_ALARM member */
    TS_InitStruct->TS_ALARM = TS_ALARM_Disable;
    /* Initialize the TS_EXTEN member */
    TS_InitStruct->TS_EXTEN = TS_ExternalTrigConvEdge_None;
    /* Initialize the TS_EXTSEL member */
    TS_InitStruct->TS_EXTSEL = TS_ExternalTrigConv_T1_TRGO;
    /* Initialize the TS_AVERAGE member */
    TS_InitStruct->TS_AVERAGE = TS_AVERAGE0;
}

/**
  * @brief  Set Analog start up time to the TS peripheral.
  * @param  TS_start_times: Analog start up time of the TS peripheral.
  *         This parameter can be: TS_ANASTUP(1us to 1.875us).
  *            @arg TS_ANASTUP0
  *            @arg TS_ANASTUP1
  *            @arg ...
  *            @arg TS_ANASTUP7
  * @retval None
  */
void TS_ANASTUP(uint32_t TS_start_times)
{
    uint32_t tmpreg = 0;
    /* Check the parameters */
    assert_param(IS_TS_ANASTUP(TS_start_times));
    tmpreg = TS->CR;
    tmpreg &= (~TS_CR_ANASTUP);
    tmpreg |= TS_start_times;
    /*Set Analog start up time to the TS peripheral */
    TS->CR = tmpreg;
}

/**
  * @brief  Set Sample delay time to the TS peripheral.
  * @param  TS_samp_dly: Sample delay timeof the TS peripheral.
  *         This parameter can be: TS_SMPDLY(1 to 16 cycles).
  *            @arg TS_SMPDLY1
  *            @arg TS_SMPDLY2
  *            @arg ...
  *            @arg TS_SMPDLY16
  * @retval None
  */
void TS_AMPDLY(uint32_t TS_samp_dly)
{
    uint32_t tmpreg = 0;
    /* Check the parameters */
    assert_param(IS_TS_SMPDLY(TS_samp_dly));
    tmpreg = TS->CR;
    tmpreg &= (~TS_CR_SMPDLY);
    tmpreg |= TS_samp_dly;
    /*Set Sample delay time to the TS peripheral */
    TS->CR = tmpreg;
}

/**
  * @brief  Set the trigger to start the TS peripheral.
  * @param  Trigger_edge: External trigger enable and polarity selection.
  *         This parameter can be:
  *            @arg TS_ExternalTrigConvEdge_None: Sofware Trigger
  *            @arg TS_ExternalTrigConvEdge_Rising
  *            @arg TS_ExternalTrigConvEdge_Falling
  *            @arg TS_ExternalTrigConvEdge_RisingFalling
  * @param  Trigger_sources: External trigger selection.
  *         This parameter can be:
  *            @arg TS_ExternalTrigConv_T1_TRGO
  *            @arg TS_ExternalTrigConv_T1_CC4
  *            @arg TS_ExternalTrigConv_T1_CC5
  *            @arg TS_ExternalTrigConv_T1_CC6
  *            @arg TS_ExternalTrigConv_T2_TRGO
  *            @arg TS_ExternalTrigConv_T3_TRGO
  *            @arg TS_ExternalTrigConv_T15_TRGO
  *            @arg TS_ExternalTrigConv_RTC_TRGO
  * @retval None
  */
void TS_TRGOEXTSEL(uint32_t Trigger_edge, uint32_t Trigger_sources)
{
    uint32_t tmpreg = 0;
    /* Check the parameters */
    assert_param(IS_TS_EXT_TRIG_EDGE(Trigger_edge));
    assert_param(IS_TS_EXTERNAL_TRIG_CONV(Trigger_sources));
    tmpreg = TS->CR;
    /*External trigger enable and polarity selection to the TS peripheral */
    tmpreg &= (~(TS_CR_EXTEN | TS_CR_EXTSEL));
    /*External trigger selection to the TS peripheral */
    tmpreg |= Trigger_edge | Trigger_sources;
    TS->CR = tmpreg;
}

/**
  * @brief  Set the High_threshold and Low_threshold to the TS peripheral.
  * @param  High_threshold: High temp threshold.
  *         This parameter can be: 9 bits Temp data
  * @param  Low_threshold: Low temp threshold.
  *         This parameter can be: 9 bits Temp data
  * @retval None
  */
void TS_THRConfig(uint16_t High_threshold, uint16_t Low_threshold)
{
    uint32_t tmpth = 0;
    /*Set the High_threshold and Low_threshold  to the TS peripheral */
    tmpth = (High_threshold << 16) + Low_threshold;
    /* Write to TS THR */
    TS->THR = tmpth;
}

/**
  * @brief  Set the Calibration Temp to the TS peripheral.
  * @param  Cal_Temp: Calibration Temp.
  *         This parameter can be: 9 bits Temp data
  * @retval None
  */
void TS_TESTMPConfig(uint16_t Cal_Temp)
{
    uint32_t Temp = 0;
    /*Set the Calibration Temp to the TS peripheral */
    Temp = (Cal_Temp << 16);
    /* Write to TS CALR */
    TS->CALR = Temp;
}

/**
  * @brief  Set the Calibration to the TS peripheral.
  * @param  Calibration: Calibration data.
  *         This parameter can be: 8 bits Temp data
  * @retval None
  */
void TS_CALRConfig(uint16_t Calibration)
{
    /* Write to TS CALR */
    TS->CALR = Calibration;
}

/**
  * @brief  To get the TS converted values.
  * @retval The Data conversion value.
  */
uint16_t TS_GetConversionValue(void)
{
    /* read conversion value */
    return (uint16_t)TS->TMPR;
}

/**
  * @brief  Calibration the TS peripheral.
  * @param  Cal_Temp: Calibration Temp.
  *         This parameter can be: 9 bits Temp data
  * @retval None
  */
uint16_t TS_GetCalibrationFactor(uint16_t Cal_Temp)
{
    uint32_t tmpreg = 0;
    uint16_t CALR_data = 0xFF;
    uint16_t CNT_CAL;
    /*reset Calibration data*/
    TS->CALR = 0;
    /*Set the Calibration Temp to the TS peripheral */
    TS->CALR = (Cal_Temp << 16);
    /* Write to TS CR  CALEN = 1, EN = 1*/
    TS->CR |= TS_CR_CALEN;
    TS->CR |= TS_CR_EN;

    /* wait TS ANARDY */
    while ((TS->ISR & TS_FLAG_ANARDY) == (uint32_t)RESET)
    {
        CNT_CAL++;
        __NOP ();

        if (CNT_CAL > CALIBRATION_TIMEOUT)
        {
            break;
        }
    }

    CNT_CAL = 0;
    TS->CR |= TS_CR_START;

    while ((TS->ISR & TS_FLAG_CALDN) == (uint32_t)RESET)
    {
        CNT_CAL++;
        __NOP ();

        if (CNT_CAL > CALIBRATION_TIMEOUT)
        {
            break;
        }
    }

    CALR_data = (uint16_t)TS->CALR;
    tmpreg = TS->CR;
    tmpreg &= (~TS_CR_EN);
    TS->CR = tmpreg;
    tmpreg = TS->CR;
    tmpreg &= (~TS_CR_CALEN);
    TS->CR = tmpreg;
    return CALR_data;
}
/**
  * @brief  Set temperature Alarm to the TS peripheral.
  * @param  TS_ALARM: temperature Alarm.
  *         This parameter can be:
  *            @arg TS_ALARM_Disable
  *            @arg TS_ALARM_Low_EN
  *            @arg TS_ALARM_High_EN
  *            @arg TS_ALARM_Low_High_BothEN
  * @retval None
  */
void TS_ALARMCmd(uint32_t TS_ALARM)
{
    uint32_t tmpreg = 0;
    /* Check the parameters */
    assert_param(IS_TS_ALARM(TS_ALARM));
    tmpreg = TS->CR;
    tmpreg &= (~TS_CR_ALARM);
    tmpreg |= TS_ALARM;
    /*Set temperature Alarm to the TS peripheral */
    TS->CR = tmpreg;
}

/**
  * @brief  Set Clock Division to the TS peripheral.
  * @param  TS_Clock_DIV: Clock Division.
  *         This parameter can be:
  *            @arg TS_ClockDIV0
  *            @arg TS_ClockDIV2
  *            @arg TS_ClockDIV4
  *            @arg TS_ClockDIV8
  *            @arg TS_ClockDIV16
  * @retval None
  */
void TS_SetClock(uint32_t TS_Clock_DIV)
{
    uint32_t tmpreg = 0;
    /* Check the parameters */
    assert_param(IS_TS_CLOCKMODE(TS_Clock_DIV));
    tmpreg = TS->CR;
    tmpreg &= (~TS_Clock_DIV);
    tmpreg |= TS_Clock_DIV;
    /*Set Clock_DIV to the TS peripheral */
    TS->CR = tmpreg;
}

/**
  * @brief  Set Average_times (oversampling) to the TS peripheral.
  * @param  TS_Average_times: oversampling times.
  *         This parameter can be:
  *            @arg TS_AVERAGE0
  *            @arg TS_AVERAGE2
  *            @arg TS_AVERAGE4
  *            @arg TS_AVERAGE8
  *            @arg TS_AVERAGE16
  * @retval None
  */
void TS_AVERAGE(uint32_t TS_Average_times)
{
    uint32_t tmpreg = 0;
    /* Check the parameters */
    assert_param(IS_TS_AVERAGE(TS_Average_times));
    tmpreg = TS->CR;
    tmpreg &= (~TS_Average_times);
    tmpreg |= TS_Average_times;
    /*Set Average_times to the TS peripheral */
    TS->CR = tmpreg;
}

/**
  * @brief  Enables or disables the specified TS peripheral.
  * @param  NewState: new state of the TS peripheral.
  *         This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void TS_Cmd(FunctionalState NewState)
{
    uint32_t tmpreg = 0;
    /* Check the parameters */
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState != DISABLE)
    {
        /* Set the EN bit to Enable the TS peripheral */
        TS->CR |= (uint32_t)TS_CR_EN;
    }
    else
    {
        tmpreg = TS->CR;
        tmpreg &= (~TS_CR_EN);
        /* Set the ADDIS to Disable the TS peripheral */
        TS->CR = tmpreg;
    }
}

/**
  * @brief  Start the TS peripheral.
  * @retval None
  */
void TS_Start(void)
{
    /* Set the START bit to Start the TS peripheral */
    TS->CR |= TS_CR_START;
}



/**
  * @}
  */

/** @defgroup TS_Group2 Interrupts and flags management functions
 *  @brief   Interrupts and flags management functions.
 *
@verbatim
 ===============================================================================
          ##### Interrupts and flags management functions #####
 ===============================================================================
    [..] This section provides functions allowing to configure the TS Interrupts
         and get the status and clear flags and Interrupts pending bits.

    [..] The TS provide 6 Interrupts sources and 11 Flags which can be divided into

  *** Flags for TS status ***
    ======================================================
        [..]
                (+)Flags :
                     (##) TS_FLAG_ANARDY : This flag is set after TS EN,
                                                                specifies the interrupt source for TS ready event.
                     (##) TS_FLAG_OVRTRIGO : This flag is set by External overrun,
                                                                specifies the interrupt source for TS OVRTRIGO event.
                     (##) TS_FLAG_HIGH : This flag is set once the High temp alarm,
                                                                specifies the interrupt source for TS High temp alarm event.
                     (##) TS_FLAG_LOW : This flag is set once the Low temp alarm,
                                                                specifies the interrupt source for TS Low temp alarm event.
                     (##) TS_FLAG_SENDN : This flag is set once the conversion is complete,
                                                                specifies the interrupt source for TS conversion is complete event.
                     (##) TS_FLAG_CALDN : This flag is set once the calibration is complete,
                                                                specifies the interrupt source for TS calibration is complete event.
@endverbatim
  * @{
  */

/**
  * @brief  Enables or disables the specified TS interrupts.
  * @param  TS_IT: specifies the TS interrupt sources to be enabled or disabled.
  *         This parameter can be one of the following values:
  *            @arg TS_IT_HIGH: TS High temp interrupt
  *            @arg TS_IT_LOW: TS Low temp interrupt
  *            @arg TS_IT_SENDN: End of conversion interrupt
  *            @arg TS_IT_OVRTRIGO: OVRTRIGO interrupt
  *            @arg TS_IT_CALDN: End of calibration interrupt
  * @param  NewState: new state of the specified TS interrupts.
  *         This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void TS_ITConfig(uint32_t TS_IT, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_FUNCTIONAL_STATE(NewState));
    assert_param(IS_TS_GET_IT(TS_IT));

    if (NewState != DISABLE)
    {
        /* Enable the selected TS interrupts */
        TS->IER |= TS_IT;
    }
    else
    {
        /* Disable the selected TS interrupts */
        TS->IER &= (~(uint32_t)TS_IT);
    }
}

/**
  * @brief  Checks whether the specified TS flag is set or not.
  * @param  TS_FLAG: specifies the flag to check.
  *         This parameter can be one of the following values:
  *            @arg TS_FLAG_OVRTRIGO: Overrun flag
  *            @arg TS_FLAG_SENDN: End of conversion flag
  *            @arg TS_FLAG_ANARDY: TS Ready flag
  *            @arg TS_FLAG_HIGH: TS High temp flag
  *            @arg TS_FLAG_LOW: TS Low temp flag
  *            @arg TS_FLAG_CALDN: TS Calibration flag
  * @retval The new state of TS_FLAG (SET or RESET).
  */
FlagStatus TS_GetFlagStatus(uint32_t TS_FLAG)
{
    FlagStatus bitstatus = RESET;
    uint32_t tmpreg = 0;
    /* Check the parameters */
    assert_param(IS_TS_GET_FLAG(TS_FLAG));

    if (TS_FLAG == TS_FLAG_ANARDY)
    {
        tmpreg = TS->CR;
    }
    else
    {
        tmpreg = TS->ISR;
    }

    /* Check the status of the specified TS flag */
    if ((tmpreg & TS_FLAG) != (uint32_t)RESET)
    {
        /* TS_FLAG is set */
        bitstatus = SET;
    }
    else
    {
        /* TS_FLAG is reset */
        bitstatus = RESET;
    }

    /* Return the TS_FLAG status */
    return  bitstatus;
}

/**
  * @brief  Clears the TS pending flags.
  * @param  TS_CLEAR_FLAG: specifies the flag to clear.
  *         This parameter can be any combination of the following values:
  *            @arg TS_FLAG_CLEAR_OVRTRIGO: Overrun flag
  *            @arg TS_FLAG_CLEAR_SENDN: End of conversion flag
  *            @arg TS_FLAG_CLEAR_HIGH: TS High temp flag
  *            @arg TS_FLAG_CLEAR_LOW: TS Low temp flag
  *            @arg TS_FLAG_CLEAR_CALDN: TS Calibration flag
  * @retval None
  */
void TS_ClearFlag(uint32_t TS_CLEAR_FLAG)
{
    /* Check the parameters */
    assert_param(IS_TS_CLEAR_FLAG(TS_CLEAR_FLAG));
    /* Clear the selected TS flags */
    TS->ISR = (uint32_t)TS_CLEAR_FLAG;
}


/**
  * @}
  */

/**
  * @}
  */
/**
 * @}
 */

/**
 * @}
 */
